-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CMS_PERMISSION: optionally use raw id user lookups #1481
Conversation
The "view restrictions" and "page permissions" inlines on the "page" admin change forms can cause performance problems where there are many thousands of users being put into simple select boxes. Added a new setting (CMS_RAW_ID_USERS) that, if set, forces the inlines on that page to use standard Django admin "raw ID" lookups rather than select boxes. The restriction on which users may be selected should still be honoured by the new widget because we set the 'limit_choices_to' attribute to be the same as the queryset on the original widget. Using raw_id_fields in combination with limit_choices_to blows up if you have many thousands of users. For this reason, we only apply this limit if the number of users is relatively small (< 500, though that figure is somewhat arbitrary). If the number of users we need to limit to is greater than that, we use the usual input field instead unless the user is a CMS superuser, in which case we bypass the limit. Unfortunately, this means that non-superusers won't see any benefit from this change.
As mentioned on the developers mailing list: https://groups.google.com/forum/#!topic/django-cms-developers/zprGZo6Pz1Y |
Ok this needs docs and it needs merge with develop. I don't think we gonna release an other 2.2 release for this. |
OK, I'll add some docs & remove the version bump. |
Also removed the previous version bump so it can merge cleanly upstream.
Looks good to me... @ojii could you have a look as well? |
|
||
limit_choices = True | ||
use_raw_id = False | ||
if hasattr(settings, 'CMS_RAW_ID_USERS') and settings.CMS_RAW_ID_USERS: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if getattr(settings, 'CMS_RAW_ID_USERS', False):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be clearer.
I have a few isuses with the patch itself, but on top of that I'm (as we all know by now) not a huge fan of adding new settings. If this is such a good thing, why don't we just make it the default? |
Good point @ojii. Remove the setting and make it an Raw ID field if there are more 500 users? Maybe even 200? |
I only made it a setting because I didn't want to alter default behaviour. With thousands of user accounts, it's currently infeasible to use CMS_PERMISSION because of the issues addressed by this patch, so making it default would make sense to me. |
please remerge with develop and i think too that the configurable limit would be better... |
@@ -26,6 +26,9 @@ | |||
# Whether to enable permissions. | |||
CMS_PERMISSION = False | |||
|
|||
# Whether to use raw ID lookups for users when CMS_PERMISSION is set to True | |||
CMS_RAW_ID_USERS = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with regards to the limit, how about making this setting either False
(disable the raw ID lookup) or an integer which is the limit?
OK, sounds good. I'll bring my branch up to date & make the limit configurable. |
@ojii should I put |
yes please |
Conflicts: cms/conf/global_settings.py
So the RAW_ID_USERS setting should now be either left as False or set to a positive integer which will be the threshold for the number of users above which the raw ID widget will be used.
@@ -27,6 +27,16 @@ class PagePermissionInlineAdmin(TabularInline): | |||
exclude = ['can_view'] | |||
extra = 0 # edit page load time boost | |||
|
|||
def __getattribute__(self, name): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github seems to have lost this discussion, but this works for me:
In [1]: class A:
...: @property
...: def b(self):
...: return []
...:
In [2]: a = A()
In [3]: isinstance(a.b, list)
Out[3]: True
In [4]: isinstance(a.b, (list, tuple))
Out[4]: True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Django checks it on the class, not an instance, otherwise it would indeed work.
https://github.com/django/django/blob/master/django/contrib/admin/validation.py#L267
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class classproperty(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, owner_self, owner_cls):
return self.fget(owner_cls)
## -- End pasted text --
In [2]: class A:
...: @classproperty
...: def b(cls):
...: return []
...:
In [3]: A.b
Out[3]: []
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so that would work, but do you think it's better than just using __getattribute__
? Up to you, but IMO the original code is easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguably, but I just really am not a fan of __getattribute__
. had too many issues with it in the past...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Let me know if this is blocking the merge and I'll change it, but my personal preference would be to leave as-is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had a chat with @digi604 and @stefanfoulis and we all three prefer classproperty
over __getattribute__
.
I think the best place to put that helper class is probably cms.utils.helpers
, so if you could change this bit to make use of that technique, that would be highly appreciated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okie doke.
Added the new classproperty helper in cms.utils.helpers.
CMS_PERMISSION: optionally use raw id user lookups
Thanks! |
Thank YOU! |
The "view restrictions" and "page permissions" inlines on the "page"
admin change forms can cause performance problems where there are many
thousands of users being put into simple select boxes. Added a new
setting (CMS_RAW_ID_USERS) that, if set, forces the inlines on that page
to use standard Django admin "raw ID" lookups rather than select boxes.
The restriction on which users may be selected should still be honoured
by the new widget because we set the 'limit_choices_to' attribute to be
the same as the queryset on the original widget.
Using raw_id_fields in combination with limit_choices_to blows up if you
have many thousands of users. For this reason, we only apply this limit
if the number of users is relatively small (< 500, though that figure is
somewhat arbitrary). If the number of users we need to limit to is
greater than that, we use the usual input field instead unless the user
is a CMS superuser, in which case we bypass the limit. Unfortunately,
this means that non-superusers won't see any benefit from this change.